/*
                    TextBox Class Implementation
*/
#include "TextBox.h"

#include "SDL/SDL_ttf.h"

TextBox::TextBox()
{
    TTFfont = NULL;
    Image = NULL;
    TTFText = NULL;
    Cursor = NULL;

    ForeColour.r = 0x00;
    ForeColour.g = 0x00;
    ForeColour.b = 0x00;

    Position = Point(0,0);
    CursorPosition = Point(0,0);

    strAltBuffer = "";

    ustrValidInput = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,<.>/?;:'\"{[}]\\|=+-_1234567890)(*&^%$#@!~`";

    iSize = 0;

    iCursorPosition = 0;
    iCameraPosition = 0;

    iWidth = 0;
    iHeight = 0;

    bPasswordbox = false;
    bHasFocus = false;
    bVisible = true;
    bEnabled = true;

    iCharacterLimit = 8;

    iRenderX = 0;
}

TextBox::~TextBox()
{
    if (TTFfont != NULL)
    {
        CloseFont(TTFfont);
        TTFfont = NULL;
    }

    SDL_FreeSurface(Image);
    SDL_FreeSurface(TTFText);
    SDL_FreeSurface(Cursor);
}

int TextBox::Initialise(Point NewPosition, string strFontFilepath, int iNewSize,
                                   int iNewPadding, string strImageFilepath, SDL_Color NewColor, int iNewCharacterLimit)
{
    iSize = iNewSize;
    iPadding = iNewPadding;

    Position = NewPosition;

    iCharacterLimit = iNewCharacterLimit;

    ForeColour = NewColor;

    TTFfont = TTF_OpenFont(strFontFilepath.c_str(), iSize);

    SDL_FreeSurface(Image);
    SDL_FreeSurface(Cursor);

    Image = OptimiseAlphaSurface(IMG_Load(strImageFilepath.c_str()));

    Cursor = OptimiseSurface(SDL_CreateRGBSurface(SDL_HWSURFACE, 1, (iSize + 3), 32,
                                   0, 0, 0, 0));

    SDL_FillRect(Cursor, NULL, 0x000000);

    UpdateTextBox();
}

int TextBox::UpdateTextBox()
{
    SDL_FreeSurface(TTFText);

    int iTemp = 0;
    int iCounter = 0;

    UnicodeString ustrShownText(ustrText);

    // If it's a password box then replace all letters with "*"
    if (bPasswordbox == true)
    {
        ustrShownText.ReplaceFill('*');
    }

    // Find cursor position
    TTF_SizeUNICODE(TTFfont, ustrShownText.SubArray(0, iCursorPosition), &iTemp, NULL);
    iTemp += iPadding;
    iTemp -= iRenderX;

    CursorPosition.x = Position.x + iTemp;
    CursorPosition.y = Position.y + iPadding;

    TTFText = OptimiseAlphaSurface(TTF_RenderUNICODE_Blended(TTFfont, ustrShownText.ToCArray(), ForeColour));

    return 0;
}

int TextBox::HandleMouseDown(int iMouseX, int iMouseY)
{
    double xpos = Position.x;
    double ypos = Position.y;

    int iWidth = Image->w;
    int iHeight = Image->h;

    if((iMouseX > xpos) && (iMouseX < xpos + iWidth) && (iMouseY > ypos) && (iMouseY < ypos + iHeight))
    {
                bHasFocus = true;

                return 1;
    }
    else
    {
        bHasFocus = false;
    }

    return 0;
}

int TextBox::HandleKeyDown(string strKeyName, Uint16 UNICODEvalue)
{
    if (bHasFocus == true)
    {
        if (strKeyName == "return")
        {
            return 1;
        }

        ParseKey(strKeyName, UNICODEvalue);

        UpdateTextBox();

        if ((CursorPosition.x - Position.x) < 0)
        {
            int iTemp = 0;
            TTF_SizeUNICODE(TTFfont, ustrText.SubArray(iCursorPosition, 1), &iTemp, NULL);

            iRenderX -= iTemp;
        }

        if ((CursorPosition.x - Position.x) > Image->w)
        {
            int iTemp = 0;
            TTF_SizeUNICODE(TTFfont, ustrText.SubArray(iCursorPosition-1, 1), &iTemp, NULL);

            iRenderX += iTemp;
        }
    }

    return 0;
}

int TextBox::ParseKey(string strKeyName, Uint16 ucharKeyName)
{
    if (strKeyName == "space")
    {
        InsertCharacter(static_cast<Uint16>(' '));
    }
    else if (strKeyName == "backspace")
    {
        EraseLetter();
    }
    else if (strKeyName == "delete")
    {
        DeleteLetter();
    }
    else if (strKeyName == "right")
    {
        MoveCursorRight();
    }
    else if (strKeyName == "left")
    {
        MoveCursorLeft();
    }
    else if (strKeyName == "tab")
    {
        for (int i = 0; i < 5; i++)
        {
            InsertCharacter(static_cast<Uint16>(' '));
        }
    }
    else if (strKeyName == "alt")
    {

    }
    else if (isInput(ucharKeyName) == true)
    {
        InsertCharacter(ucharKeyName);
    }
}

int TextBox::InsertCharacter(Uint16 ucharKeyName)
{
    if (ustrText.size() < iCharacterLimit)
    {
        int iTemp = 0;
        TTF_SizeUNICODE(TTFfont, UnicodeString(ucharKeyName).ToCArray(), &iTemp, NULL);

        if (TTFText != NULL)
        {
            if ((TTFText->w + iTemp) > (Image->w - (iPadding*2)))
            {
                iRenderX += iTemp;
            }
        }

        ustrText.insert(iCursorPosition, ucharKeyName);
        MoveCursorRight();
    }

    return 0;
}

int TextBox::MoveCursorRight()
{
     if (iCursorPosition < ustrText.size())
     {
          iCursorPosition++;
     }

     return 0;
}

int TextBox::MoveCursorLeft()
{
    if (iCursorPosition > 0)
    {
        iCursorPosition--;
    }

    return 0;
}

int TextBox::EraseLetter()
{
    if (ustrText.size() > 0)
    {
        if (iCursorPosition > 0)
        {
            ustrText.erase(iCursorPosition-1);
            MoveCursorLeft();
        }
    }

    return 0;
}

int TextBox::DeleteLetter()
{
    if (ustrText.size() > 0)
    {
        if (iCursorPosition > 0)
        {
            if (ustrText.size() > iCursorPosition)
            {
                ustrText.erase(iCursorPosition);
            }
        }
    }

    return 0;
}

bool TextBox::isInput(Uint16 ucharKeyName)
{
    if (ustrValidInput.size() == 0)
    {
        return true;
    }

    for (int i = 0; i < ustrValidInput.size(); i++)
    {
        if (ustrValidInput.at(i) == ucharKeyName) { return true; }
    }

    return false;
}

void TextBox::setPosition(Point NewPosition)
{
     Position = NewPosition;

     UpdateTextBox();
}

Point TextBox::getPosition()
{
    return Position;
}

void TextBox::setValidInput(string strNewValidInput)
{
    ustrValidInput = strNewValidInput;
}

UnicodeString& TextBox::getValidInput()
{
    return ustrValidInput;
}

void TextBox::setText(string strNewText)
{
    ustrText = strNewText;
    iCursorPosition = ustrText.size();

    iRenderX = 0;

    UpdateTextBox();
}

string TextBox::getText()
{
    return ustrText.ToString();
}

bool TextBox::HasFocus()
{
     return bHasFocus;
}

void TextBox::setPasswordbox(bool bNewVal)
{
    bPasswordbox = bNewVal;
}

UnicodeString TextBox::getString()
{
    return ustrText;
}

int TextBox::BlitToSurface(SDL_Surface *screen)
{
    if (bVisible == true)
    {
        SDL_Rect dest, srcRect, clip, lastclip;

        dest.x = static_cast<int>(Position.x);
        dest.y = static_cast<int>(Position.y);
        SDL_BlitSurface(Image, NULL, screen, &dest);

        clip.x = dest.x;
        clip.y = dest.y;
        clip.w = Image->w;
        clip.h = Image->h;

        SDL_GetClipRect(screen, &lastclip);
        SDL_SetClipRect(screen, &clip);

        srcRect.x = iRenderX;
        srcRect.y = 0;
        srcRect.h = Image->h;
        srcRect.w = Image->w;

        dest.x = static_cast<int>(Position.x + iPadding);
        dest.y = static_cast<int>(Position.y + iPadding);
        SDL_BlitSurface(TTFText, NULL, screen, &dest);

        if (bHasFocus == true)
        {
            dest.x = static_cast<int>(CursorPosition.x);
            dest.y = static_cast<int>(CursorPosition.y);
            SDL_BlitSurface(Cursor, NULL, screen, &dest);
        }

        SDL_SetClipRect(screen, &lastclip);
    }
}

int TextBox::BlitToFrame(SDL_Surface *surface, Point FramePosition)
{
    if (bVisible == true)
    {
        SDL_Rect dest, srcRect, clip, lastclip;

        dest.x = static_cast<int>(Position.x) + static_cast<int>(FramePosition.x);
        dest.y = static_cast<int>(Position.y) + static_cast<int>(FramePosition.y);
        SDL_BlitSurface(Image, NULL, surface, &dest);

        clip.x = dest.x;
        clip.y = dest.y;
        clip.w = Image->w;
        clip.h = Image->h;

        SDL_GetClipRect(surface, &lastclip);
        SDL_SetClipRect(surface, &clip);

        srcRect.x = iRenderX;
        srcRect.y = 0;
        srcRect.h = Image->h;
        srcRect.w = Image->w;

        dest.x = static_cast<int>(Position.x + iPadding) + static_cast<int>(FramePosition.x);
        dest.y = static_cast<int>(Position.y + iPadding) + static_cast<int>(FramePosition.y);
        SDL_BlitSurface(TTFText, &srcRect, surface, &dest);

        if (bHasFocus == true)
        {
            dest.x = static_cast<int>(CursorPosition.x) + static_cast<int>(FramePosition.x);
            dest.y = static_cast<int>(CursorPosition.y) + static_cast<int>(FramePosition.y);
            SDL_BlitSurface(Cursor, NULL, surface, &dest);
        }

        SDL_SetClipRect(surface, &lastclip);
    }
}
